# database.py
import os
import json
import zlib
import httpx
import asyncio
from typing import Any, Dict
from datetime import datetime
from sqlalchemy.orm import Session
from sqlalchemy.ext.declarative import declarative_base
from fastapi import HTTPException, Query, Request
from sqlalchemy.orm import sessionmaker
from app.supply import DATA_PATH, log
from sqlalchemy import (
    create_engine,
    Column,
    Integer,
    String,
    Boolean,
    DateTime,
    ForeignKey,
    text,
    and_,
)


# 数据库配置
SQLALCHEMY_DATABASE_URL = "sqlite:////data/database/db.sqlite"
engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}  # 仅 SQLite 需要
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()


# -------------------- 表模型定义 --------------------
class Audio(Base):
    __tablename__ = "audios"

    id = Column(Integer, primary_key=True, autoincrement=True)
    favorite = Column(Boolean, default=False, nullable=False)
    year = Column(String, nullable=True)
    language = Column(String, nullable=True)
    album = Column(String, nullable=True)
    artist = Column(String, nullable=True)
    album_id = Column(String, nullable=True)  # Drift 原字段: albumId
    artist_id = Column(String, nullable=True)  # Drift 原字段: artistId
    title = Column(String, nullable=True)
    letter = Column(String, nullable=True)
    track_number = Column(Integer, nullable=True)  # Drift 原字段: trackNumber
    lyric = Column(Integer, nullable=True)
    bitrate = Column(Integer, nullable=True)
    samplerate = Column(Integer, nullable=True)
    suffix = Column(String, nullable=True)
    url = Column(String, nullable=True)
    size = Column(Integer, nullable=True)
    file = Column(String, nullable=True)
    cover = Column(String, nullable=True)
    genre = Column(String, nullable=True)
    duration = Column(Integer, nullable=True)
    last_played = Column(DateTime, nullable=True)  # Drift 原字段: lastPlayed
    category = Column(Integer, ForeignKey("categorys.id"), nullable=True)
    extra = Column(String, nullable=True)
    source_type = Column(Integer, nullable=False)  # Drift 原字段: sourceType
    hash = Column(Integer, nullable=True)


class Category(Base):
    __tablename__ = "categorys"

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=True)
    description = Column(String, nullable=True)


class SearchHistory(Base):
    __tablename__ = "search_historys"

    id = Column(Integer, primary_key=True, autoincrement=True)
    keyword = Column(String, nullable=False)


class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, autoincrement=True)
    type = Column(Integer, nullable=False)
    server_url = Column(String, nullable=False)  # Drift 原字段: serverUrl
    username = Column(String, nullable=False)
    password = Column(String, nullable=False)
    music_path = Column(String, nullable=False)  # Drift 原字段: musicPath
    last_login = Column(DateTime, nullable=False)  # Drift 原字段: lastLogin
    expires = Column(DateTime, nullable=True)
    access_token = Column(String, nullable=True)  # Drift 原字段: accessToken
    refresh_token = Column(String, nullable=True)  # Drift 原字段: refreshToken


# -------------------- 初始化数据库（可选） --------------------
def create_tables():
    Base.metadata.create_all(bind=engine)


if __name__ == "__main__":
    create_tables()


def dart_string_hash_code(s: str) -> int:
    return zlib.crc32(s.encode("utf-8"))


def bulk_insert_audios(metadata_list: list[dict], session: Session):
    try:
        # 使用 bulk_insert_mappings 提高性能
        session.query(Audio).delete()
        session.bulk_insert_mappings(Audio, metadata_list)
        session.commit()
        log(f"批量插入 {len(metadata_list)} 条成功")
    except Exception as e:
        session.rollback()
        log(f"批量插入失败: {str(e)}")


async def get_audios(params: dict, session: Session):
    try:
        # 获取查询参数
        type = params.get("type", "all")
        letter = params.get("letter")
        page = int(params.get("page", 0))  # 默认第1页
        limit = int(params.get("limit", 100))  # 默认每页10条
        keyword = None if len(params.get("keyword", "")) == 0 else params.get("keyword")

        # 计算偏移量
        offset = page * limit
        if page == -1:
            offset = 0
            limit = 1000000

        # 动态构建过滤条件
        filters = [Audio.category == 0]

        if type == "album":
            filters.append(Audio.album_id == keyword)
            if letter is not None:
                filters.append(Audio.letter == letter)
        elif type == "artist":
            filters.append(Audio.artist_id == keyword)
            if letter is not None:
                filters.append(Audio.letter == letter)
        elif type == "tracklist":
            filters[0] = Audio.category == keyword
        elif type == "genre":
            filters.append(Audio.genre == keyword)
            if letter is not None:
                filters.append(Audio.letter == letter)
        elif type == "search":
            filters.append(Audio.title.contains(keyword or ""))
        elif type == "favorite":
            filters.append(Audio.favorite == True)
            if keyword is not None:
                filters.append(Audio.title.contains(keyword))

        # 执行查询
        if filters:
            query = session.query(Audio).filter(and_(*filters))
        else:
            query = session.query(Audio)

        # 分页
        audios = query.offset(offset).limit(limit).all()

        # 返回结果
        return audios

    except ValueError as e:
        # 处理 page 或 limit 不是整数的情况
        raise HTTPException(status_code=400, detail="Invalid page or limit value")
    except Exception as e:
        # 处理其他异常
        raise HTTPException(status_code=500, detail=str(e))


async def get_albums(params: dict, session: Session):
    try:
        base_sql = """SELECT DISTINCT a1.album, a1.album_id AS id,
                    (SELECT artist FROM audios AS a4 WHERE a4.album = a1.album AND a4.category = 0 LIMIT 1) AS artist,
                    (SELECT artist_id FROM audios AS a5 WHERE a5.album = a1.album AND a5.category = 0 LIMIT 1) AS artist_id,
                    (SELECT COUNT(*) FROM audios AS a2 WHERE a2.album = a1.album AND a2.category = 0) AS song_count,
                    (SELECT cover FROM audios AS a3 WHERE a3.album = a1.album AND a3.category = 0 AND a3.cover IS NOT NULL LIMIT 1) AS cover
                    FROM audios AS a1 
                    JOIN (SELECT album, MAX(id) AS latest_audio_id FROM audios WHERE category = 0 GROUP BY album) AS latest_audios
                    ON a1.album = latest_audios.album AND a1.id = latest_audios.latest_audio_id 
                    WHERE a1.category = 0"""
        favorite_sql = """SELECT DISTINCT album, album_id AS id,
                    (SELECT artist FROM audios AS a4 WHERE a4.album = a1.album AND a4.category = 0 LIMIT 1) AS artist,
                    (SELECT artist_id FROM audios AS a5 WHERE a5.album = a1.album AND a5.category = 0 LIMIT 1) AS artist_id,
                    (SELECT COUNT(*) FROM audios AS a2 WHERE a2.album = a1.album AND a2.category = 0) AS song_count,
                    (SELECT cover FROM audios AS a3 WHERE a3.album = a1.album AND a3.category = 0 AND a3.cover IS NOT NULL LIMIT 1) AS cover
                    FROM audios AS a1
                    WHERE a1.category = 0
                        AND a1.album IN (
                        SELECT album
                        FROM audios
                        WHERE category = 0
                        GROUP BY album
                        HAVING COUNT(*) = SUM(favorite = 1)
                        )"""

        type = params.get("type", "all")
        page = int(params.get("page", 0))  # 默认第1页
        limit = int(params.get("limit", 100))  # 默认每页10条
        keyword = params.get("keyword", "")
        letter = params.get("letter", "")

        # 计算偏移量
        offset = page * limit
        if page == -1:
            offset = 0
            limit = 1000000
        limit_clause = f" ORDER BY latest_audios.latest_audio_id DESC"

        # 根据类型查询数据
        if type == "parent":
            sql = text(f"{base_sql} AND a1.artist_id = '{keyword}'{limit_clause}")
        elif type == "single":
            sql = text(f"{base_sql} AND a1.album_id = '{keyword}'")
        elif type == "search":
            sql = text(f"{base_sql} AND a1.album LIKE '%{keyword}%'")
        elif type == "favorite":
            sql = text(favorite_sql)
        else:
            sql = text(f"{base_sql}{limit_clause}")

        # 执行查询
        result = session.execute(sql, {"limit": limit, "offset": offset})
        albums = [dict(row._asdict()) for row in result]

        # 返回结果
        return albums

    except Exception as e:
        # 处理其他异常
        raise HTTPException(status_code=500, detail=str(e))


async def get_artists(params: dict, session: Session):
    try:
        base_sql = """SELECT DISTINCT a1.artist, a1.artist_id AS id,
                    (SELECT cover FROM audios AS a3 WHERE a3.artist = a1.artist AND a3.category = 0 AND a3.cover IS NOT NULL ORDER BY a3.id DESC LIMIT 1) AS cover,
                    (SELECT COUNT(DISTINCT album) FROM audios AS a4 WHERE a4.artist = a1.artist AND a4.category = 0) AS album_count,
                    (SELECT COUNT(*) FROM audios AS a5 WHERE a5.artist = a1.artist AND a5.category = 0) AS song_count
                    FROM audios AS a1 JOIN (SELECT artist, MAX(id) AS latest_audio_id FROM audios WHERE category = 0 GROUP BY artist) AS latest_audios
                    ON a1.artist = latest_audios.artist AND a1.id = latest_audios.latest_audio_id WHERE a1.category = 0"""
        favorite_sql = """SELECT DISTINCT  artist, artist_id AS id,
                    (SELECT cover FROM audios AS a3 WHERE a3.artist = a1.artist AND a3.category = 0 AND a3.cover IS NOT NULL LIMIT 1) AS cover,
                    (SELECT COUNT(DISTINCT album) FROM audios AS a4 WHERE a4.artist = a1.artist AND a4.category = 0) AS album_count,
                    (SELECT COUNT(*) FROM audios AS a5 WHERE a5.artist = a1.artist AND a5.category = 0) AS song_count
                    FROM audios AS a1
                    WHERE a1.category = 0
                    AND a1.album IN (
                      SELECT album
                      FROM audios
                      WHERE category = 0
                      GROUP BY album
                      HAVING COUNT(*) = SUM(favorite = 1)
                    )"""
        type = params.get("type", "all")
        page = int(params.get("page", 0))  # 默认第1页
        limit = int(params.get("limit", 100))  # 默认每页10条
        letter = params.get("letter", "")
        keyword = params.get("keyword", "")

        # 计算偏移量
        offset = page * limit
        if page == -1:
            offset = 0
            limit = 1000000
        limit_clause = f" ORDER BY latest_audios.latest_audio_id DESC"

        # 根据类型查询数据
        if type == "favorite":
            sql = text(favorite_sql)
        elif type == "single":
            sql = text(f"{base_sql} AND a1.artist_id = '{keyword}'")
        elif type == "search":
            sql = text(f"{base_sql} AND a1.artist LIKE '%{keyword}%'")
        else:
            sql = text(f"{base_sql}{limit_clause}")

        # 执行查询
        result = session.execute(sql, {"limit": limit, "offset": offset})
        albums = [dict(row._asdict()) for row in result]

        # 返回结果
        return albums

    except Exception as e:
        # 处理其他异常
        raise HTTPException(status_code=500, detail=str(e))


async def get_genres(params: dict, session: Session):
    try:
        base_sql = """WITH RECURSIVE genres AS (
                      SELECT DISTINCT
                        id,  -- 添加 id 列以确保每条记录的唯一性
                        genre, 
                        TRIM(SUBSTR(genre, 1, CASE WHEN INSTR(genre, '/') = 0 THEN LENGTH(genre) ELSE INSTR(genre, '/') - 1 END)) AS single_genre,
                        CASE WHEN INSTR(genre, '/') = 0 THEN '' ELSE TRIM(SUBSTR(genre, INSTR(genre, '/') + 1)) END AS remaining_genre
                      FROM audios
                      WHERE genre IS NOT NULL AND genre != '' AND category = 0
                      UNION ALL
                      SELECT
                        g.id,  -- 保持 id 列的一致性
                        g.genre,
                        TRIM(SUBSTR(g.remaining_genre, 1, CASE WHEN INSTR(g.remaining_genre, '/') = 0 THEN LENGTH(g.remaining_genre) ELSE INSTR(g.remaining_genre, '/') - 1 END)) AS single_genre,
                        CASE WHEN INSTR(g.remaining_genre, '/') = 0 THEN '' ELSE TRIM(SUBSTR(g.remaining_genre, INSTR(g.remaining_genre, '/') + 1)) END AS remaining_genre
                      FROM genres g
                      WHERE g.remaining_genre != ''
                    ),
                    all_genres AS (
                      SELECT 
                        id,
                        COALESCE(single_genre, '') AS genre
                      FROM genres
                      WHERE single_genre != ''
                      UNION ALL
                      SELECT 
                        id,
                        '' AS genre
                      FROM audios
                      WHERE (genre IS NULL OR genre = '') AND category = 0
                    )
                    SELECT 
                      genre,
                      COUNT(DISTINCT id) AS song_count
                    FROM all_genres
                    GROUP BY genre"""
        favorite_sql = """WITH RECURSIVE genres AS (
                          SELECT DISTINCT
                            id,  -- 添加 id 列以确保每条记录的唯一性
                            genre, 
                            TRIM(SUBSTR(genre, 1, CASE WHEN INSTR(genre, '/') = 0 THEN LENGTH(genre) ELSE INSTR(genre, '/') - 1 END)) AS single_genre,
                            CASE WHEN INSTR(genre, '/') = 0 THEN '' ELSE TRIM(SUBSTR(genre, INSTR(genre, '/') + 1)) END AS remaining_genre
                          FROM audios
                          WHERE genre IS NOT NULL AND genre != ''
                          UNION ALL
                          SELECT
                            g.id,  -- 保持 id 列的一致性
                            g.genre,
                            TRIM(SUBSTR(g.remaining_genre, 1, CASE WHEN INSTR(g.remaining_genre, '/') = 0 THEN LENGTH(g.remaining_genre) ELSE INSTR(g.remaining_genre, '/') - 1 END)) AS single_genre,
                            CASE WHEN INSTR(g.remaining_genre, '/') = 0 THEN '' ELSE TRIM(SUBSTR(g.remaining_genre, INSTR(g.remaining_genre, '/') + 1)) END AS remaining_genre
                          FROM genres g
                          WHERE g.remaining_genre != ''
                        ),
                        all_genres AS (
                          SELECT 
                            id,
                            COALESCE(single_genre, '') AS genre
                          FROM genres
                          WHERE single_genre != ''
                          UNION ALL
                          SELECT 
                            id,
                            '' AS genre
                          FROM audios
                          WHERE genre IS NULL OR genre = ''
                        )
                        SELECT 
                          ag.genre,
                          COUNT(DISTINCT a1.id) AS songCount
                        FROM all_genres ag
                        JOIN audios a1 ON ag.id = a1.id
                        WHERE a1.category = 0
                          AND a1.album IN (
                            SELECT album
                            FROM audios
                            WHERE category = 0
                            GROUP BY album
                            HAVING COUNT(*) = SUM(favorite = 1)
                          )
                        GROUP BY ag.genre;"""
        search_sql = """WITH RECURSIVE genres AS (
                      SELECT DISTINCT
                        id,  -- 添加 id 列以确保每条记录的唯一性
                        genre,
                        TRIM(SUBSTR(genre, 1, CASE WHEN INSTR(genre, '/') = 0 THEN LENGTH(genre) ELSE INSTR(genre, '/') - 1 END)) AS single_genre,
                        CASE WHEN INSTR(genre, '/') = 0 THEN '' ELSE TRIM(SUBSTR(genre, INSTR(genre, '/') + 1)) END AS remaining_genre
                      FROM audios
                      WHERE genre IS NOT NULL AND genre != ''
                      UNION ALL
                      SELECT
                        g.id,  -- 保持 id 列的一致性
                        g.genre,
                        TRIM(SUBSTR(g.remaining_genre, 1, CASE WHEN INSTR(g.remaining_genre, '/') = 0 THEN LENGTH(g.remaining_genre) ELSE INSTR(g.remaining_genre, '/') - 1 END)) AS single_genre,
                        CASE WHEN INSTR(g.remaining_genre, '/') = 0 THEN '' ELSE TRIM(SUBSTR(g.remaining_genre, INSTR(g.remaining_genre, '/') + 1)) END AS remaining_genre
                      FROM genres g
                      WHERE g.remaining_genre != ''
                    ),
                    all_genres AS (
                      SELECT
                        id,
                        COALESCE(single_genre, '') AS genre
                      FROM genres
                      WHERE single_genre != ''
                      UNION ALL
                      SELECT
                        id,
                        '' AS genre
                      FROM audios
                      WHERE genre IS NULL OR genre = ''
                    )
                    SELECT
                      ag.genre,
                      COUNT(DISTINCT a1.id) AS songCount
                    FROM all_genres ag
                    JOIN audios a1 ON ag.id = a1.id
                    WHERE a1.category = 0
                      AND a1.album IN (
                        SELECT album
                        FROM audios
                        WHERE category = 0
                        GROUP BY album
                        HAVING COUNT(*) = SUM(favorite = 1)
                      )
                      AND a1.genre LIKE '%$keyword%'
                    GROUP BY ag.genre;"""

        type = params.get("type", "all")
        keyword = params.get("keyword", "")

        # 根据类型查询数据
        if type == "favorite":
            sql = text(favorite_sql)
        if type == "search":
            search_sql = search_sql.replace("keyword", keyword)
            sql = text(search_sql)
        else:
            sql = text(base_sql)

        # 执行查询
        result = session.execute(sql)
        albums = [dict(row._asdict()) for row in result]

        # 返回结果
        return albums

    except Exception as e:
        # 处理其他异常
        raise HTTPException(status_code=500, detail=str(e))


async def get_playlists(params: dict, session: Session):
    try:
        base_sql = """ SELECT 
                    c.id AS id,
                    c.name AS name,
                    c.description AS description,
                    (SELECT a.cover 
                    FROM audios AS a 
                    WHERE a.category = c.id AND a.cover IS NOT NULL 
                    LIMIT 1) AS cover,
                    (SELECT COUNT(*) 
                    FROM audios AS a 
                    WHERE a.category = c.id) AS audio_count
                FROM 
                    categorys AS c
                WHERE c.name LIKE :keyword"""
        favorite_sql = """ SELECT 
                    c.id AS id,
                    c.name AS name,
                    c.description AS description,
                    (SELECT a.cover 
                    FROM audios AS a 
                    WHERE a.category = c.id AND a.cover IS NOT NULL AND a.favorite = true 
                    LIMIT 1) AS cover,
                    (SELECT COUNT(*) 
                    FROM audios AS a 
                    WHERE a.category = c.id AND a.favorite = true) AS audio_count
                FROM 
                    categorys AS c
                WHERE
                    c.id IN (
                        SELECT a.category
                        FROM audios AS a
                        GROUP BY a.category
                        HAVING COUNT(*) = SUM(a.favorite = true)
                    )"""

        type = params.get("type", "all")
        keyword = params.get("keyword", "")

        if type == "favorite":
            sql = text(favorite_sql)
        else:
            if keyword:
                sql = text(base_sql)
                sql = sql.bindparams(keyword=f"%{keyword}%")
            else:
                base_sql = base_sql.replace("WHERE c.name LIKE :keyword", "")
                sql = text(base_sql)

        # 执行查询
        result = session.execute(sql)
        playlists = [dict(row._asdict()) for row in result]
        return playlists

    except Exception as e:
        # 处理其他异常
        raise HTTPException(status_code=500, detail=str(e))


async def get_search(params: dict, session: Session):
    keyword = params.get("keyword", "")
    tasks = [
        get_audios(params={"type": "search", "keyword": keyword}, session=session),
        get_audios(params={"type": "favorite", "keyword": keyword}, session=session),
        get_albums(params={"type": "search", "keyword": keyword}, session=session),
        get_artists(params={"type": "search", "keyword": keyword}, session=session),
        get_playlists(params={"type": "search", "keyword": keyword}, session=session),
        get_genres(params={"type": "search", "keyword": keyword}, session=session),
    ]

    audios, favorites, albums, artists, playlists, genres = await asyncio.gather(*tasks)

    return {
        "audios": audios,
        "favorites": favorites,
        "albums": albums,
        "artists": artists,
        "playlists": playlists,
        "genres": genres,
    }


async def get_favorites(session: Session):
    tasks = [
        get_audios(params={"type": "favorite"}, session=session),
        get_albums(params={"type": "favorite"}, session=session),
        get_artists(params={"type": "favorite"}, session=session),
        get_playlists(params={"type": "favorite"}, session=session),
        get_genres(params={"type": "favorite"}, session=session),
    ]

    audios, albums, artists, playlists, genres = await asyncio.gather(*tasks)

    return {
        "audios": audios,
        "albums": albums,
        "artists": artists,
        "playlists": playlists,
        "genres": genres,
    }


async def get_lyric(hash: int, session: Session):
    try:
        lyric_extensions = ["qrc", "krc", "lrc"]

        for ext in lyric_extensions:
            base_dir = DATA_PATH / f"lyrics/{hash}.{ext}"
            if base_dir.exists():
                try:
                    with open(base_dir, "r", encoding="utf-8") as f:
                        text = f.read()
                        return {"text": text, "ext": ext}
                except Exception as e:
                    raise HTTPException(
                        status_code=500,
                        detail=f"Failed to read lyric file: {str(e)}",
                    )

        audio = session.query(Audio).filter(Audio.hash == hash).first()
        if audio:
            audio_path = audio.url
            if audio.url.startswith("hp_localhost/stream?url="):
                audio_path = audio.url.split("hp_localhost/stream?url=")[1]
            if os.path.exists(audio_path):
                for ext in lyric_extensions:
                    base_dir = f"{os.path.splitext(audio_path)[0]}.{ext}"
                    if os.path.exists(base_dir):
                        try:
                            with open(base_dir, "r", encoding="utf-8") as f:
                                text = f.read()
                                return {"text": text, "ext": ext}
                        except Exception as e:
                            raise HTTPException(
                                status_code=500,
                                detail=f"Failed to read lyric file: {str(e)}",
                            )

        return {"text": "", "ext": ""}

    except httpx.HTTPStatusError as e:
        return {"error": str(e)}, e.response.status_code
    except Exception as e:
        return {"error": str(e)}, 500


async def set_lyric(data: Dict[str, Any]):
    hash = data["hash"]
    text = data["text"]
    ext = data["ext"]
    exts = [".qrc", ".krc", ".lrc"]

    # 构造歌词文件的基础路径
    lyric_dir = DATA_PATH / "lyrics"
    lyric_path = lyric_dir / f"{hash}{ext}"

    try:
        # 确保歌词目录存在
        lyric_dir.mkdir(parents=True, exist_ok=True)

        # 移除所有可能存在的旧歌词文件
        for old_ext in exts:
            old_file = lyric_dir / f"{hash}{old_ext}"
            if old_file.exists():
                old_file.unlink()  # 删除文件

        # 写入新的歌词文件
        with open(lyric_path, "w", encoding="utf-8") as f:
            f.write(text)

        return {"message": "Lyric saved successfully"}

    except Exception as e:
        raise HTTPException(
            status_code=500, detail=f"Failed to save lyric file: {str(e)}"
        )


async def get_backup(
    session: Session, recent: bool = Query(False), playlist: bool = Query(False)
):
    try:

        query = session.query(Audio)

        filters = []
        if recent == False:
            filters.append(Audio.category != 1)
        if playlist == False:
            filters.append(Audio.category != 2)
        if filters:
            query = session.query(Audio).filter(and_(*filters))
        else:
            query = session.query(Audio)

        audios = query.all()

        categorys = session.query(Category).all()
        search_historys = session.query(SearchHistory).all()
        users = session.query(User).all()

        return {
            "audios": audios,
            "categorys": categorys,
            "search_historys": search_historys,
            "users": users,
        }

    except httpx.HTTPStatusError as e:
        return {"error": str(e)}, e.response.status_code
    except Exception as e:
        return {"error": str(e)}, 500


async def set_backup(request: Request, data: Dict[str, Any], session: Session):
    try:

        session.query(Audio).delete()
        session.query(Category).delete()
        session.query(SearchHistory).delete()
        session.query(User).delete()

        audios = data["audios"]
        for audio in audios:
            print(audio["cover"])
            # if "host:5146" in audio["cover"]:
            #     print(audio["cover"])
        categorys = data["categorys"]
        search_historys = data["search_historys"]
        users = data["users"]

        session.bulk_insert_mappings(Audio, audios)
        session.bulk_insert_mappings(Category, categorys)
        session.bulk_insert_mappings(SearchHistory, search_historys)
        for user in users:
            if "last_login" in user and isinstance(user["last_login"], int):
                user["last_login"] = datetime.fromtimestamp(user["last_login"] / 1000)
            if "expires" in user and isinstance(user["expires"], int):
                user["expires"] = datetime.fromtimestamp(user["expires"] / 1000)
        session.bulk_insert_mappings(User, users)
        session.commit()

    except httpx.HTTPStatusError as e:
        return {"error": str(e)}, e.response.status_code
    except Exception as e:
        return {"error": str(e)}, 500
